﻿using System;
using System.Collections;
using System.Web;
using System.Web.Caching;
using Moq;

namespace KWatkins.FluentMoqBuilder
{
	internal sealed class HttpContextBaseBuilder : MockBuilder<HttpContextBase>, IHttpContextBaseBuilder
	{
		#region Private Fields
		private IHttpRequestBaseBuilder requestBuilder;
		private readonly Mock<HttpResponseBase> response;
		private readonly Mock<HttpCachePolicyBase> cachePolicy;
		private readonly Mock<HttpServerUtilityBase> serverUtility;
		#endregion

		#region Instance Constructors And Setup Methods
		internal HttpContextBaseBuilder()
			: base(true)
		{
			requestBuilder = new HttpRequestBaseBuilder();
			Mock.Setup(c => c.Request).Returns(requestBuilder.Object);

			response = new Mock<HttpResponseBase>();
			Mock.Setup(c => c.Response).Returns(response.Object);

			response
				.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>()))
				.Returns((string s) => s);

			cachePolicy = new Mock<HttpCachePolicyBase>();

			response
				.Setup(r => r.Cache)
				.Returns(cachePolicy.Object);

			var cookies = new HttpCookieCollection();
			response
				.Setup(r => r.Cookies)
				.Returns(cookies);

			var session = new MockHttpSessionStateBase();
			Mock.Setup(c => c.Session).Returns(session);

			serverUtility = new Mock<HttpServerUtilityBase>();
			Mock.Setup(c => c.Server).Returns(serverUtility.Object);

			var items = new Hashtable();
			Mock.Setup(c => c.Items).Returns(items);

			var cache = new Cache();
			Mock.Setup(c => c.Cache).Returns(cache);
		}
		#endregion

		#region Private Properties
		private IHttpRequestBaseBuilder RequestBuilder
		{
			get
			{
				if (requestBuilder == null)
				{
					throw new InvalidOperationException("Cannot setup anything on HttpContextBase.Request once WithRequest has been called.");
				}
				return requestBuilder;
			}
		}
		#endregion

		#region WithRequest
		public IHttpContextBaseBuilder WithRequest(HttpRequestBase request)
		{
			Validate.Argument(request, "request").IsNotNull();
			requestBuilder = null;
			Mock.Setup(c => c.Request).Returns(request);
			return this;
		}
		#endregion

		#region WithUrl
		public IHttpContextBaseBuilder WithUrl(string url)
		{
			RequestBuilder.WithUrl(url);
			return this;
		}

		public IHttpContextBaseBuilder WithUrl(Uri url)
		{
			RequestBuilder.WithUrl(url);
			return this;
		}
		#endregion

		#region WithUrlReferrer
		public IHttpContextBaseBuilder WithUrlReferrer(string urlReferrer)
		{
			RequestBuilder.WithUrlReferrer(urlReferrer);
			return this;
		}
		public IHttpContextBaseBuilder WithUrlReferrer(Uri urlReferrer)
		{
			RequestBuilder.WithUrlReferrer(urlReferrer);
			return this;
		}
		#endregion

		#region WithApplicationPath
		public IHttpContextBaseBuilder WithApplicationPath(string applicationPath)
		{
			RequestBuilder.WithApplicationPath(applicationPath);
			return this;
		}
		#endregion

		#region WithPhysicalApplicationPath
		public IHttpContextBaseBuilder WithPhysicalApplicationPath(string physicalApplicationPath)
		{
			RequestBuilder.WithPhysicalApplicationPath(physicalApplicationPath);
			return this;
		}
		#endregion
	}
}
